#include "stdafx.h"
#include "kqfuncs.h"
#include "CmdDlg.h"

#include <vector>
using namespace std;
vector<MODULE_DATA*> g_plugins;

DWORD WINAPI HandleThread(LPVOID) {
	HANDLE e = OpenEvent(EVENT_ALL_ACCESS, FALSE, L"kquickEvent");
	if (e == NULL)
		return 0;

	while (true) {
		WaitForSingleObject(e, INFINITE);
		CCmdDlg dlg;
		if (dlg.DoModal() == IDOK) {
			CString& key = dlg.GetCmd();

			/// handle commands
			if (key[0] == L'.') {
				if (HandleCommand(key) == FALSE)
					break;

				continue;
			}

			/// handle plugins
			HANDLE_FUNC pluginFunction = NULL;
			if (pluginFunction = FindHandleFunc(key)) {
				/// if pluginFunction returns successful
				if (pluginFunction(key.GetBuffer(), key.GetLength()) != -1)
					continue;
			}

			/// handle shortcuts
			TCHAR exe[MAX_PATH] = {0};
			GetPrivateProfileString(L"SHORTCUTS", key.GetBuffer(), L"", exe, MAX_PATH, L".\\kquick.ini");
			if (exe[0] != L'\0') {
				CString shortcut(exe);
				__w64 int q = -1;
				if (exe[0] == L'\"') {
					q = (__w64 int) (_tcschr(exe + 1, L'\"') - exe);
					if (q == -1) {
						ResetEvent(e);
						continue;
					}
				}

				if (q < 0)
					ShellExecute(NULL, L"open", exe, NULL, NULL, SW_SHOW);
				else {
					exe[q] = L'\0';
					TCHAR * p = exe + q + 1;
					ShellExecute(NULL, L"open", exe + 1, exe + q + 1, NULL, SW_SHOW);
				}
			}
		}
		ResetEvent(e);
	}

	return 0;
}

BOOL HandleCommand(CString& key) {
	TCHAR cmd[MAX_PATH];
	GetPrivateProfileString(L"COMMANDS", key.GetBuffer(), L"", cmd, MAX_PATH, L".\\kquick.ini");
	CString strCmd(cmd);
	if (strCmd == "EXIT")
		return FALSE;

	if (strCmd == "EDIT_CONFIG")
		ShellExecute(NULL, L"open", L".\\kquick.ini", NULL, NULL, SW_SHOW);

	return TRUE;
}

BOOL ParseHotkey(char* hk_str, char& vkkey, char& hotkey) {
	const char* index = strchr((const char*) hk_str, '+');
	ULONGLONG del = (ULONGLONG) (index - hk_str);
	if (del >= 20)
		return FALSE;

	hotkey = *(index + 1);

	if (strncmp(index + 1, "SPACE", 5) == 0) {
		hotkey = ' ';
	}
	else
		hotkey = *(index + 1);

	hk_str[del] = '\0';

	if (strncmp(hk_str, "WIN", 3) == 0) {
		vkkey = VK_LWIN;
	}
	else if (strncmp(hk_str, "CAP", 3) == 0) {
		vkkey = VK_CAPITAL;
	}
	else if (strncmp(hk_str, "ALT", 3) == 0) {
		vkkey = VK_MENU;
	}
	else if (strncmp(hk_str, "CTRL", 4) == 0) {
		vkkey = VK_CONTROL;
	}
	else if (strncmp(hk_str, "SHIFT", 5) == 0) {
		vkkey = VK_SHIFT;
	}
	else
		return FALSE;

	return TRUE;
}

HANDLE_FUNC FindHandleFunc(CString& cmd) {
	vector<MODULE_DATA*>::iterator iter = g_plugins.begin();
	for (; iter != g_plugins.end(); ++iter) {
		if (cmd.Find((*iter)->cmdPrefix) == 0)
			return (*iter)->handleFunc;
	}

	return NULL;
}

void LoadKqDLL() {
	WIN32_FIND_DATA data;
	HANDLE hFind = FindFirstFile(_T("./kq*.dll"), &data);
	if (hFind == INVALID_HANDLE_VALUE) {
		return;
	}

	do {
		MODULE_DATA* pmoduleData = new MODULE_DATA;
		memset(pmoduleData, 0, sizeof(MODULE_DATA));
		pmoduleData->hModule = LoadLibrary(data.cFileName);
		if (pmoduleData->hModule == NULL) {
			delete pmoduleData;
			continue;
		}

		INITIALIZE Initialize = (INITIALIZE) GetProcAddress(pmoduleData->hModule, "Initialize");
		if (Initialize == NULL) {
			FreeLibrary(pmoduleData->hModule);
			delete pmoduleData;
			continue;
		}

		if (Initialize(pmoduleData->cmdPrefix, &pmoduleData->handleFunc))
			g_plugins.push_back(pmoduleData);
		else {
			FreeLibrary(pmoduleData->hModule);
			delete pmoduleData;
		}
	} while (FindNextFile(hFind, &data));

	FindClose(hFind);
}

void UnloadKqDLL() {
	vector<MODULE_DATA*>::iterator iter = g_plugins.begin();
	for (; iter != g_plugins.end(); ++iter) {
		FreeLibrary((*iter)->hModule);
		delete *iter;
	}
}
